/*
	This file is part of "Ants on the web".

    "Ants on the web" is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    "Ants on the web" is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with "Ants on the web".  If not, see <http://www.gnu.org/licenses/>.
*/

package org.utc.ia04.antsontheweb.pheromone;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;


/**
 * Find the usage from main()
 * @author JI Wenyao
 */
public class NetGraphic {

	public static final int PH_INC_PATH = 10;
	private int size;
	
	private LinkedHashMap<URL, Node> nodeList;
	private List<Node> path;
	private URL antColonyUrl;
	
	public NetGraphic(URL parAntColonyUrl)
	{
		//TODO ajouter security exception si parAntColony == null
		antColonyUrl = parAntColonyUrl;
		size = 0;
		nodeList = new LinkedHashMap<URL, Node>();
		path = new ArrayList<Node>();
	}
	
	/**
	 * insert a node in the graphic
	 * @param oldUrl is the url before this node, if this is the first node, oldNode = null
	 * @param newUrl is the current url
	 */
//	public void insertNode(URL oldUrl, URL newUrl)
//	{
//		Node newNode = null;
//		
//		if(oldUrl == null)
//		{
//			newNode = new Node(newUrl);
//			nodeList.put(newUrl, newNode);
//		}
//		else
//		{	
//			Node node = nodeList.get(oldUrl);
//			if(node != null)
//			{
//				newNode = new Node(newUrl);
//				node.addNextNode(newNode);
//				newNode.addNextNode(node);
//				nodeList.put(newUrl, newNode);
//			}
//			else
//				System.out.println("ERROR : oldUrl doesn't exist");
//		}
//	}
	
	public void insertNode(URL currentUrl, URL nextUrl, boolean currentTarget, boolean nextTarget)
	{
		if(nodeList.containsKey(currentUrl))
		{
			if(nodeList.containsKey(nextUrl))
			{
				Node currentNode = nodeList.get(currentUrl);
				Node nextNode = nodeList.get(nextUrl);
				if(currentNode != null && nextNode != null)
				{
					//currentNode.addNextNode(nextNode);
					nextNode.addNextNode(currentNode);
				}
				
			}
			else
			{
				Node currentNode = nodeList.get(currentUrl);
				if(currentNode != null)
				{
					Node nextNode = new Node(nextUrl, nextTarget);
					//currentNode.addNextNode(nextNode);
					nextNode.addNextNode(currentNode);
					nodeList.put(nextUrl,nextNode);
				}
				else
					System.out.println("ERROR : oldUrl doesn't exist");
			}
			
		}
		else
		{
			if(nodeList.containsKey(nextUrl))
			{
				Node nextNode = nodeList.get(nextUrl);
				if(nextNode != null)
				{
					Node currentNode = new Node(currentUrl, currentTarget);
					//currentNode.addNextNode(nextNode);
					nextNode.addNextNode(currentNode);
					nodeList.put(currentUrl, currentNode);
				}
				else
					System.out.println("ERROR : nextNode doesn't exist");
			}
			else
			{
				Node currentNode = new Node(currentUrl, currentTarget);
				Node nextNode = new Node(nextUrl, nextTarget);
				//currentNode.addNextNode(nextNode);
				nextNode.addNextNode(currentNode);
				nodeList.put(currentUrl, currentNode);
				nodeList.put(nextUrl, nextNode);
			}
		}
	}
	
	public void changePheromone(URL url, double ph)
	{
		Node node = nodeList.get(url);
		if(node != null)
			node.setPheromone(ph);
		else
			System.out.println("ERROR : url doesn't exist");
	}
	
	public void incrementePheromone(URL url)
	{
		changePheromone(url,nodeList.get(url).getPheromone()+ PH_INC_PATH);
	}
	
	public HashMap<URL, Double> getLinksWithPheromone(Set<URL> urls)
	{
		HashMap<URL, Double> answer = new HashMap<URL, Double>();
		for(URL url : urls)
		{
			Node node = nodeList.get(url);
			if(node != null)
			{
//				try
//				{
					Double d = new Double(node.getPheromone());
					answer.put(url, d);
//				}
//				catch (MalformedURLException e)
//				{
//					System.out.println("Erreur dans getLinksWithPheromone : " + e.toString());
//				}
			}
			else
			{
				answer.put(url, 0.);
			}
		}
		
		return answer;
	}
	
	public Node getMorePheromoneNode(Set<Node> set)
	{
		Node res = null;
		if(set.isEmpty())
		{
			System.out.println("ERROR : getNextNodes empty");
			return null;
		}
		
		Node deletedNode = null;
		for(Node node : set)
			if(path.contains(node))
				deletedNode = node;

		set.remove(deletedNode);
		
		if(set.isEmpty())
		{
			System.out.println("ERROR : this is the last node");
			return null;
		}
		
//		res = set.get(0);
//		for(Node node : set)
//			if(res.getPheromone() < node.getPheromone())
//				res = node;

		Iterator<Node> it=set.iterator();
		 //on cr�e un Iterator pour parcourir notre HashSet
		double max = 0;
		while(it.hasNext()) // tant qu'on a un suivant
		{
			Node node = it.next();
			if(node.getPheromone() > max)
			{
				max = node.getPheromone();
				res = node;
			}	
		}
		return res;
	}
	
	public URL getMorePheromoneNodeByURL(Set<URL> urls){
		URL res = null;
		Set<Node> temp = new HashSet<Node>();
		
		for(URL url : urls){
			/*for(Node node : nodeList){
				if(url.equals(node.getUrl())){
					temp.add(node);
					break;
				}
			}*/
			Node node = nodeList.get(url);
			if(node != null){
				temp.add(node);
			} else{
				System.out.println("node error! = null");
			}
		}
		
		if(temp.isEmpty()){
			return null;
		}
		
		Node node = getMorePheromoneNode(temp);
		res = node.getUrl();
		
		return res;
	}
	
	/**
	 * The method to find the shortest path from source to destination about the pheromone.
	 * Example : getShortestPath("www.utc.fr","www.amazon.fr",null);
	 * @param source url
	 * @param destination url
	 * @param currentNode to use this fonction, this input is always "null"
	 * @return list of the node through the path
	 */
	public List<Node> getShortestPath(String source, String destination, Node currentNode)
	{
		if(currentNode == null){
			path.clear();
			
			/*for(Node n : nodeList){
				if(n.getUrl().equals(source)){
					currentNode = n;
					path = getShortestPath(source, destination, n);
				}
			}*/
			
			Node node = nodeList.get(source);
			if(node != null){
				currentNode = node;
				path = getShortestPath(source, destination, node);
			} else{
				System.out.println("no source error");
			}
			
			if(currentNode == null){
				System.out.println("ERROR : source error");
				return null;
			}
			
		} else{
			path.add(currentNode);
			if(currentNode.getUrl().equals(destination)){
				return path;
			}
			
			Node nextNode = getMorePheromoneNode(currentNode.getNextNodes());
			if(nextNode == null){
				System.out.println("ERROR : fail to find the destination");
				return path;
			}
			
			path = getShortestPath(source, destination, nextNode);
		}
		
		return path;
	}
	
	public List<Node> findNearestResourceProvider()
	{
		List<Node> pathResult = new ArrayList<Node>();
		Node currentNode = nodeList.get(antColonyUrl);
		pathResult.add(currentNode);
		if (currentNode == null)
			return null;
		do
		{
			Set<Node> nextNodes = currentNode.getNextNodes();
			//parcour de la liste des noeuds suivants de currentNode
			
			//On choisit celui qui a le plus fort taux de ph�romones
			//si il n'y en a pas, on met nextNode �1�7 null et fin de la boucle
			Iterator<Node> it=nextNodes.iterator();
			double max = 0;
			while(it.hasNext()) 
			{
				Node node = it.next();
				if (pathResult.contains(node))
					continue;
				if(node.getPheromone() >= max)
				{
					max = node.getPheromone();
					currentNode = node;
				}					
			}
			//ajouter ce node dans la liste
			try { pathResult.add(currentNode); }
			catch(Exception e) { System.out.println("Error computing the solution..."); }

		}while (currentNode.isTarget() != true);//changer la condition d'arret
		return pathResult;
	}
	/**
	 * to serialize the urls
	 * @param list of the url normally returned by fonction getShortestPath();
	 * @return String to send to interface for displaying the result
	 */
	public static List<String> getPathString(List<Node> list)
	{
		List<String> listOfUrl = new ArrayList<String>();
		for(Node n : list)
			listOfUrl.add(n.getUrl().toString());
		return listOfUrl;
	}
	
	public static List<URL> getPathURL(List<Node> list)
	{
		List<URL> listOfUrl = new ArrayList<URL>();
		for(Node n : list)
			listOfUrl.add(n.getUrl());
		return listOfUrl;
	}
	
	/* Test
	public void printResultToTest(){
		for(Node node : nodeList.values()){
			System.out.println(node.getUrl() + " ph = " + node.getPheromone());
			for(Node n : node.getNextNodes()){
				System.out.println("next node: " + n.getUrl());
			}
			System.out.println("-----------------------");
		}
	} */
	
	public int getSize() {
		return size;
	}
	public void setSize(int size) {
		this.size = size;
	}
	/*public List<Node> getNodeList() {
		return nodeList;
	}
	public void setNodeList(List<Node> nodeList) {
		this.nodeList = nodeList;
	}*/
	
	public LinkedHashMap<URL, Node> getNodeList() {
		return nodeList;
	}

	public void setNodeList(LinkedHashMap<URL, Node> nodeList) {
		this.nodeList = nodeList;
	}

	public URL getAntColonyUrl() {
		return antColonyUrl;
	}
	
	/* Test
	public static void main(String[] args) {
		NetGraphic g = new NetGraphic();
		g.insertNode(null, "www.utc.fr");
		g.insertNode("www.utc.fr", "www.google.fr");
		g.insertNode("www.utc.fr", "www.lemonde.fr");
		g.insertNode("www.google.fr", "www.amazon.fr");
		g.changePheromone("www.google.fr", 1.2);
		
		for(Node node : g.getNodeList().values()){
			System.out.println(node.getUrl() + " ph = " + node.getPheromone());
			for(Node n : node.getNextNodes()){
				System.out.println("next node: " + n.getUrl());
			}
			System.out.println("-----------------------");
		}
		
		//Node node = NetGraphic.getMorePheromoneNode(g.getNodeList().get(0).getNextNodes());
		//System.out.println(node.getUrl());
		
		List<Node> res = g.getShortestPath("www.utc.fr", "www.amazon.fr", null);
		System.out.println(getPathString(res));
		//String[] urls = {"www.google.fr","www.lemonde.fr"};
		//System.out.println(g.getMorePheromoneNodeByURL(urls));
	} */
}
